package com.hex.ds.hdtp.core.app.data.contrast.service.impl;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hex.ds.hdtp.core.app.common.enums.BasicListStatus;
import com.hex.ds.hdtp.core.app.common.enums.BasicTaskStatus;
import com.hex.ds.hdtp.core.app.common.enums.CrossDbContrastResultContrastType;
import com.hex.ds.hdtp.core.app.data.contrast.dto.CrossDbContrastDto;
import com.hex.ds.hdtp.core.app.data.contrast.dto.CrossDbContrastResultDto;
import com.hex.ds.hdtp.core.app.data.contrast.service.*;
import com.hex.ds.hdtp.core.inf.data.contrast.po.CrossDbContrastRunLogPo;
import com.hex.ds.hdtp.core.inf.data.contrast.repository.ICrossDbContrastRunLogRepository;
import com.hex.ds.hdtp.core.inf.data.contrast.repository.ICrossDbContrastTaskRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;


/**
 * @Package com.hex.ds.hdtp.core.app.data.contrast.service.impl
 * @ClassName CrossDbContrastService
 * @Description 跨库比对-业务接口实现
 * @Author Wang zhihao
 * @Date 2023/8/6 22:07
 * @Version v1.0
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CrossDbContrastService implements ICrossDbContrastService {

    private final IContrastTableStructureService contrastTableStructure;

    private final IContrastDataSummaryService contrastDataSummary;

    private final IContrastSampleDataService contrastSampleData;

    private final ICrossDbContrastCommonService crossDbContrastCommonService;

    private final ICrossDbContrastListService crossDbContrastListService;

    private final ICrossDbContrastRunLogService crossDbContrastRunLogService;

    private final ICrossDbContrastRunLogRepository crossDbContrastRunLogRepository;

    private final ICrossDbContrastTaskRepository crossDbContrastTaskRepository;
    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void setThreadLocal(String value) {
        threadLocal.set(value);
    }

    public static String getThreadLocal() {
        return threadLocal.get();
    }

    public void unload() {
        threadLocal.remove(); // Compliant
    }

    /**
     * @Method contrast
     * @Param [crossDbContrastDto]
     * @Return void
     * @Description 跨库对比
     * @Author Wang zhihao
     * @Date 2023/7/19 11:17
     * @Version V1.0
     */
    @Override
    @Async("dataContrastAsyncTaskExecutor")
    public void contrast(CrossDbContrastDto crossDbContrastDto, String runLogPkId) {
        String source = crossDbContrastDto.getContrastCommon().getSourceSchema() + "." + crossDbContrastDto.getContrastCommon().getSourceTable();
        String contrast = crossDbContrastDto.getContrastCommon().getContrastSchema() + "." + crossDbContrastDto.getContrastCommon().getContrastTable();
        if (isTaskStopped(runLogPkId)) return;
        setThreadLocal(StrUtil.format("[{}-{}{}#Task]", source, contrast, Thread.currentThread().getName().substring(Thread.currentThread().getName().lastIndexOf("-"))));
        try {
            boolean sampleData = false;
            //1.表结构比对
            if (isTaskStopped(runLogPkId)) return;
            boolean tableStructure = contrastTableStructure.contrastTableStructure(crossDbContrastDto.getContrastCommon(), crossDbContrastDto.getContrastTableStructure(), runLogPkId);
            //2.数量汇总比对
            if (isTaskStopped(runLogPkId)) return;
            boolean dataSummary = contrastDataSummary.contrastDataSummary(crossDbContrastDto.getContrastCommon(), crossDbContrastDto.getContrastDataSummary(), runLogPkId);
            //3.全字段明细比对
            if (isTaskStopped(runLogPkId)) return;
            sampleData = contrastAllFieldsDetail(crossDbContrastDto, runLogPkId, dataSummary, tableStructure, sampleData);
            if (isTaskStopped(runLogPkId)) return;
            Boolean contrastResult = tableStructure && dataSummary && sampleData;
            // 更新清单状态
            crossDbContrastListService.modifyStatus(crossDbContrastDto.getContrastCommon().getContrastListPkId(), contrastResult.toString());
            // 更新比对记录
            modifyContrastRunLog(runLogPkId, contrastResult);
        } catch (Exception e) {
            log.error("数据比对【{}】失败，失败原因:{}", source + "-" + contrast, e.getMessage(), e);
            crossDbContrastListService.modifyStatus(crossDbContrastDto.getContrastCommon().getContrastListPkId(), Boolean.FALSE.toString());
            modifyContrastRunLog(runLogPkId, Boolean.FALSE);
        } finally {
            log.info("数据比对【{}】结束，结束时间:{}", source + "-" + contrast, DateUtil.now());
            // 查询比对记录更新任务
            CrossDbContrastRunLogPo recentByTask = crossDbContrastRunLogRepository.queryById(runLogPkId);
            crossDbContrastTaskRepository.updateCountById(recentByTask);
            if (BasicTaskStatus.FINISH.name().equals(recentByTask.getStatus())) {
                crossDbContrastTaskRepository.updateEndStatusById(recentByTask.getTaskPkId());
            }
        }
    }

    /**
     * @Method contrastAllFieldsDetail
     * @Param crossDbContrastDto
     * @Param runLogPkId
     * @Param dataSummary
     * @Param tableStructure
     * @Param sampleData
     * @Return boolean
     * @Description 全字段明细比对
     * @Author gj.xu
     * @Date 2024/2/23 11:41
     * @Version V2.0
     */
    private boolean contrastAllFieldsDetail(CrossDbContrastDto crossDbContrastDto, String runLogPkId, boolean dataSummary, boolean tableStructure, boolean sampleData) {
        if (dataSummary) {
            if (crossDbContrastDto.getContrastCommon().getTableTransferPkId() == null && !tableStructure) {
                crossDbContrastCommonService.addContrastResult(crossDbContrastDto.getContrastCommon(), runLogPkId, CrossDbContrastResultContrastType.IS_ALL_FIELD.getName(),
                        BasicListStatus.FAIL.name(), "未经历表迁移且表结构对比有误，不进行全字段明细比对");
            } else {
                //3.1-1 全字段明细比对
                sampleData = contrastSampleData.contrastSampleData(crossDbContrastDto.getContrastCommon(), crossDbContrastDto.getContrastSampleData(), runLogPkId);
            }
        } else {
            //3.1-2 表内容比对失败 跳过 全字段明细比对 直接置为失败
            CrossDbContrastResultDto crossDbContrastResultDto = tableStructure ? new CrossDbContrastResultDto().setContrastResult(false).setSampleData("数据量比对有误，不进行全字段明细比对") : new CrossDbContrastResultDto().setContrastResult(false).setSampleData("表结构比对有误，不进行全字段明细比对");
            crossDbContrastCommonService.addContrastResult(crossDbContrastDto.getContrastCommon(), runLogPkId, CrossDbContrastResultContrastType.IS_ALL_FIELD.getName(),
                    BasicListStatus.FAIL.name(), crossDbContrastResultDto.getSampleData());
        }
        return sampleData;
    }

    /**
     * @Method isTaskStopped
     * @Param runLogPkId
     * @Return boolean
     * @Description 判断任务是否停止
     * @Author gj.xu
     * @Date 2024/2/22 20:06
     * @Version V2.0
     */
    private boolean isTaskStopped(String runLogPkId) {
        return crossDbContrastRunLogService.queryStatusByPkId(runLogPkId) != null && crossDbContrastRunLogService.queryStatusByPkId(runLogPkId).equalsIgnoreCase(BasicTaskStatus.STOPPED.name());
    }

    /**
     * @Method checkTaskFinish
     * @Param pkId
     * @Return void
     * @Description 检查比对任务状态
     * @Author gj.xu
     * @Date 2024/1/11 20:35
     * @Version V2.0
     */
    @Override
    public void checkTaskFinish(String pkId) {
        // 判断比对记录无运行中，则将任务置为完成
        if (crossDbContrastRunLogRepository.queryByTaskIdStatus(pkId, BasicTaskStatus.PROCESSING.name()).size() <= 0) {
            crossDbContrastTaskRepository.modifyTaskFinish(pkId, BasicTaskStatus.FINISH.name());
        }
    }


    private void modifyContrastRunLog(String runLogPkId, Boolean result) {
        if (result.equals(Boolean.TRUE)) {
            crossDbContrastRunLogService.modifySuccessNum(runLogPkId);
        } else {
            crossDbContrastRunLogService.modifyFailNum(runLogPkId);
        }
    }
}
